#include "test.h"

#include <string.h>
#include <stdlib.h>
#include <fen.h>
#include <position.h>


#define FEN_TEST(id, pos, ok) RUN_TEST("FEN_" id, test_fen_position, pos, ok)
#define EPD_TEST(id, pos, ok) RUN_TEST("EPD_" id, test_epd_position, pos, ok)


static int test_epd_position(const char* epd, int ok)
{
  const int maxbuflen = 120;
  char newepd[maxbuflen];
  position_t pos;
  const char** opts = 0;
  
  opts = decode_epd(epd, &pos);
  if (ok) {
    TEST_ASSERT(opts != 0);
    
    for (int buflen = 0; buflen < maxbuflen; buflen++) {
      memset(newepd, 'X', maxbuflen);
      int n = encode_epd(&pos, newepd, buflen, opts);
      TEST_ASSERT_GOTO(n == strlen(epd), error);
      for (int j = 0; j < n && j < buflen - 1; j++)
	TEST_ASSERT_GOTO(newepd[j] == epd[j], error);
      TEST_ASSERT_GOTO(buflen == 0 || (newepd[(n < buflen) ? n : (buflen - 1)] == 0), error);
    }
  } else {
    TEST_ASSERT(opts == 0);
  }

  free(opts);
  return 1;

 error:
  free(opts);
  return 0;
}

static int test_fen_position(const char* fen, int ok)
{
  const int maxbuflen = 80;
  char newfen[maxbuflen];
  position_t pos;

  if (ok) {
    TEST_ASSERT(decode_fen(fen, &pos));
    
    for (int buflen = 0; buflen < maxbuflen; buflen++) {
      memset(newfen, 'X', maxbuflen);
      int n = encode_fen(&pos, newfen, buflen);
      TEST_ASSERT(n == strlen(fen));
      for (int j = 0; j < n && j < buflen - 1; j++)
	TEST_ASSERT(newfen[j] == fen[j]);
      TEST_ASSERT(buflen == 0 || (newfen[(n < buflen) ? n : (buflen - 1)] == 0));
    }
  } else {
    TEST_ASSERT(!decode_fen(fen, &pos));
  }
  return 1;
}


void test_fen()
{
  // well formed FEN
  FEN_TEST("OK01", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 1);
  FEN_TEST("OK02", "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b Qkq e3 1 2", 1);
  FEN_TEST("OK03", "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b Kkq e3 0 1", 1);
  FEN_TEST("OK04", "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQq c6 0 2", 1);
  FEN_TEST("OK05", "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQk - 1 2", 1);
  FEN_TEST("OK06", "4k3/8/8/8/8/8/4P3/4K3 w - - 5 39", 1);
  FEN_TEST("OK07", "r1bqkb1r/pp3ppp/2n1pn2/2pp4/4PP2/2NP1N2/PPP3PP/R1BQKB1R w KQ - 0 6", 1);
  FEN_TEST("OK08", "r1bqk2r/pp2bppp/2n1pn2/2pp4/4PP2/2NP1NP1/PPPB3P/R2QKB1R b Kk - 0 7", 1);
  FEN_TEST("OK09", "r3k2r/1b1qbp1p/pnn1p1p1/1pppP3/5P2/2PP1NP1/PP2NBBP/R2Q1RK1 b kq - 0 14", 1);

  // ill formed FEN
  FEN_TEST("ERR01", "rnbqkbnr/ppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 0);
  FEN_TEST("ERR02", "rnbqkbnr/pp1ppppp/8/2p3/4P3/5N2/PPPP1PPP/RNBQKB1R b Qkq e3 1 2", 0);
  FEN_TEST("ERR03", "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b Kukq e3 0 1", 0);
  FEN_TEST("ERR04", "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR KQq c6 0 2", 0);
  FEN_TEST("ERR05", "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQk 1 2", 0);
  FEN_TEST("ERR06", "4k3/8/8/8/8/8/4P3/4K3 w - - 5 39 4", 0);
  FEN_TEST("ERR07", "r1bqkb1r/pp3ppp/2n1pn2/2pp4/4PP2/2NP1N2/PPP3PP/R1BQKB1R w KQ e2 0 6", 0);
  FEN_TEST("ERR08", "r1bqk2r/pp2bppp/2n1pn2/2pp4/4PP2/2NP1NP1/PPPB3P/R2QKB1R b Kk - 0 -7", 0);
  FEN_TEST("ERR09", "r3k2r/1b1qbp1p/pnn1p1p1/1pppP3/5P2/PP2NBBP/R2Q1RK1 b kq - 0 14", 0);
  FEN_TEST("ERR10", "r1bqk2r/8/2n1pn2/2pp4/4PP2/4PP2/2NP1NP1/PPPB3P/R2QKB1R b Kk - 0 7", 0);

  // well formed EPD
  EPD_TEST("OK01", "6k1/pp2rp1p/2p2bp1/1n1n4/1PN3P1/P2rP2P/R3NPK1/2B2R2 w - - id \"a\";", 1);
  EPD_TEST("OK02", "8/2p2kpp/p6r/4Pp2/1P2pPb1/2P3P1/P2B1K1P/4R3 w - - bm h4; id \"0 1\";", 1);
  EPD_TEST("OK03", "Q5k1/5pp1/5n1p/2b2P2/8/5N1P/5PP1/2q1B1K1 b - - hmvc 10; fmvc \" 4\";", 1);
  EPD_TEST("OK04", "r7/pp1bpp2/1n1p2pk/1B3P2/4P1P1/2N5/PPP5/1K5R b - - bm Kg5; id \"E\";", 1);
  EPD_TEST("OK05", "r1b1k2r/p1pp1ppp/1np1q3/4P3/1bP5/1P6/PB1NQPPP/R3KB1R b KQkq -", 1);
  EPD_TEST("OK06", "8/2p2kpp/p6r/4Pp2/1P2pPb1/2P3P1/P2B1K1P/4R3 w - - boh;", 1);
  EPD_TEST("OK07", "Q5k1/5pp1/5n1p/2b2P2/8/5N1P/5PP1/2q1B1K1 b - - pv Kh7 e4; id \"A B\";", 1);

  // ill formed EPD
  EPD_TEST("ERR01", "6k1/pp2rp1p/2p2bp1/1n1n4/1PN3P1/P2rP2P/R3NPK1/2B2R2 w - - id \"a;", 0);
  EPD_TEST("ERR02", "8/2p2kpp/p6r/4Pp2/1P2pPb1/2P3P1/P2B1K1P/4R3 w - - bm \"; id \"0 1\";", 0);
  EPD_TEST("ERR03", "Q5k1/5pp1/5n1p/2b2P2/8/5P/5PP1/2q1B1K1 b - - bm Kh7; id \"sbd.032\"", 0);
  EPD_TEST("ERR04", "r7/pp1bpp2/1n1p2pk/1B3P2/4P1P1/2N5/PPP5/1K5R b - bm Kg5; id \"E\";", 0);
  EPD_TEST("ERR05", "r1b1k2r/p1pp1ppp/1np1q3/4P3/1bP5/1P6/PB1NQPPP/R3KB1R KQkq -", 0);
  EPD_TEST("ERR06", "8/2p2kpp/p6r/4Pp2/1P2pPb1/2P3P1/P2B1K1P/4R3 w - - boh", 0);
  EPD_TEST("ERR07", "Q5k1/5pp1/5n1p/2b2P2/8/5N1P/5PP1/2q1B1K1 b - - pv Kh7 e4;   id \"A\";", 0);
}
